package com.yupao.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupao.common.UserConstant;
import com.yupao.exception.BusinessException;
import com.yupao.mapper.TeamMapper;
import com.yupao.mapper.UserTeamMapper;
import com.yupao.model.dto.TeamDTO;
import com.yupao.model.dto.TeamJoinRequest;
import com.yupao.model.dto.TeamQuitRequest;
import com.yupao.model.dto.TeamUpdateRequest;
import com.yupao.model.entity.Team;

import com.yupao.model.entity.User;
import com.yupao.model.entity.UserTeam;
import com.yupao.model.enums.ErrorCode;
import com.yupao.model.enums.TeamStatusEnum;
import com.yupao.model.vo.LoginUserVO;
import com.yupao.model.vo.UserTeamVO;
import com.yupao.model.vo.UserVO;
import com.yupao.service.UserTeamService;
import com.yupao.service.TeamService;
import com.yupao.service.UserService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author wangzhi
 * @description 针对表【team(队伍表)】的数据库操作Service实现
 * @createDate 2024-09-22 16:45:10
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team> implements TeamService {

    @Resource
    private UserTeamMapper userTeamMapper;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private UserService userService;

    @Override
    public Long addTeam(TeamDTO team, LoginUserVO loginUser) {

        //1.请求参数是否为空
        if (ObjectUtils.isEmpty(team)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //2.是否登录
        if (ObjectUtils.isEmpty(loginUser)) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        //队伍主键id
        Long teamId = team.getId();
        Long userId = loginUser.getId();
        //3.校验信息
        //3.1队伍人数大于等于1小于等于20
        Integer maxNum = team.getMaxNum();
        if (maxNum < 1 || maxNum > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不符合要求");
        }

        //3.2队伍标题小于等于20,不能为空
        String name = team.getName();
        if (name.isEmpty() || name.length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不符合要求");
        }

        //3.3描述小于等于512
        String description = team.getDescription();
        if (description.length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述不符合要求");
        }

        //3.4是否公开status 加密下一定会有密码 切不能为空 密码小于等于20
        Integer status = team.getStatus();
        String password = team.getPassword();
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getStatus(status);
        if (ObjectUtils.isEmpty(teamStatusEnum)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不符合要求");
        }

        if (TeamStatusEnum.SECRET.equals(teamStatusEnum)) {
            if (ObjectUtils.isEmpty(password) || password.length() > 20 || password.length() < 3) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍密码不符合要求");
            }
        }

        //超时时间大于当前时间
        LocalDateTime expireTime = team.getExpireTime();
        if (ObjectUtils.isNotEmpty(expireTime) && LocalDateTime.now().isBefore(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍日期不符合要求");
        }

        //校验当前用户最多可以创建5个队伍
        Long teamNum = userTeamService.lambdaQuery().eq(UserTeam::getUserId, userId).count();
        if (teamNum > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户创建队伍超出最大个数");
        }


        Team insertTeam = new Team();
        BeanUtils.copyProperties(team, insertTeam);
        //当前用户id
        insertTeam.setUserId(userId);
        //4.插入队伍信息到队伍表
        boolean result = this.save(insertTeam);
        if (!result) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍创建失败");
        }

        //5.插入队伍用户信息到队伍用户信息表
        UserTeam userTeam = new UserTeam();
        //回显
        userTeam.setTeamId(insertTeam.getId());
        userTeam.setUserId(userId);
        userTeam.setJoinTime(LocalDateTime.now());
        userTeamMapper.insert(userTeam);

        return insertTeam.getId();
    }


    @Override
    public List<UserTeamVO> listTeams(TeamDTO teamDTO) {
        if (ObjectUtils.isEmpty(teamDTO)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 校验队伍的状态
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        if (teamDTO.getStatus() == null) {
            teamDTO.setStatus(TeamStatusEnum.PUBLIC.getCode());
        } else {
            TeamStatusEnum status = TeamStatusEnum.getStatus(teamDTO.getStatus());
            if (ObjectUtils.isEmpty(status)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "查询状态不符合要求");
            }
            if (!userService.isAdmin(request) && TeamStatusEnum.PRIVATE.equals(status)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "用户权限不符合要求");
            }
        }

        /*
           1、队伍名称 模糊
           2、描述 模糊
           3、最大人数 等于
           4、创建人id 等于
           5、过期时间 不查询过期的队伍，不过期和为空符合
           6、0-公开 1-私有 2-加密 不查询私有的队伍，管理员可以
         */
        LambdaQueryWrapper<Team> wrapper = new LambdaQueryWrapper<>();
        if (teamDTO.getSearchText() != null) {
            wrapper.like(Team::getName, teamDTO.getSearchText())
                    .or()
                    .like(Team::getDescription, teamDTO.getSearchText());
        }

        //1、队伍名称 模糊
        if (teamDTO.getName() != null) {
            wrapper.like(Team::getName, teamDTO.getName());
        }

        //2、描述 模糊
        if (teamDTO.getDescription() != null) {
            wrapper.like(Team::getDescription, teamDTO.getDescription());
        }

        //3、最大人数 小于等于
        if (teamDTO.getMaxNum() != null) {
            wrapper.le(Team::getMaxNum, teamDTO.getMaxNum());
        }

        //4、创建人id 等于
        if (teamDTO.getUserId() != null) {
            wrapper.eq(Team::getUserId, teamDTO.getUserId());
        }

        //5、过期时间 不查询过期的队伍，不过期和为空符合
        if (teamDTO.getExpireTime() != null && teamDTO.getExpireTime().isAfter(LocalDateTime.now())) {
            wrapper.ge(Team::getExpireTime, teamDTO.getExpireTime());
        } else if (teamDTO.getExpireTime() == null) {
            wrapper.ge(Team::getExpireTime, LocalDateTime.now());
        }

        //6、0-公开 1-私有 2-加密 不查询私有的队伍，管理员可以
        if (teamDTO.getStatus() != null) {
            wrapper.eq(Team::getStatus, teamDTO.getStatus());
        }

        List<Team> teamList = this.list(wrapper);


       /* List<Team> teamList = this.lambdaQuery()
                .like(teamDTO.getSearchText() != null, Team::getName, teamDTO.getSearchText())
                .or()
                .like(teamDTO.getSearchText() != null, Team::getDescription, teamDTO.getSearchText())
                .like(teamDTO.getName() != null, Team::getName, teamDTO.getName())
                .or()
                .like(teamDTO.getDescription() != null, Team::getDescription, teamDTO.getDescription())
                .eq(teamDTO.getMaxNum() != null, Team::getMaxNum, teamDTO.getMaxNum())
                .eq(teamDTO.getUserId() != null, Team::getUserId, teamDTO.getUserId())
                .eq(teamDTO.getStatus() != null ,Team::getStatus, teamDTO.getStatus())
                .gt(teamDTO.getExpireTime() != null ,Team::getExpireTime, teamDTO.getExpireTime())
                .or()
                .isNull(Team::getExpireTime)
                .list();*/

        //为空没查到返回一个空的集合
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }

        //转换成返回的实体，进行返回
        List<UserTeamVO> userTeamVOList = new ArrayList<>();
        for (Team team : teamList) {
            Long userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            User user = userService.getById(userId);
            if (user == null) {
                continue;
            }

            //转成安全用户
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);

            UserTeamVO userTeamVO = new UserTeamVO();
            BeanUtils.copyProperties(team, userTeamVO);

            //todo 把所有的成员都显示出来
            userTeamVO.setCreateUserVO(userVO);
            userTeamVOList.add(userTeamVO);
        }

        return userTeamVOList;
    }

    @Override
    public boolean updateTeam(TeamUpdateRequest teamUpdateRequest) {

        if (ObjectUtils.isEmpty(teamUpdateRequest)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //1.用户是否登录 取session中的attribute
        LoginUserVO loginUser = userService.getLoginUser();
        if (ObjectUtils.isEmpty(loginUser)) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        //2.查询队伍是否存在
        Long teamId = teamUpdateRequest.getId();
        Team team = this.getById(teamId);
        if (ObjectUtils.isEmpty(team)) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "修改队伍不存在");
        }

        //3.只有管理员和队伍创建者可以修改
        Integer userRole = loginUser.getUserRole();
        if (!userRole.equals(UserConstant.USER_ADMIN) && !Objects.equals(teamUpdateRequest.getUserId(), loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }

        //5.如果队伍状态改成加密，则必须要有密码
        Integer status = teamUpdateRequest.getStatus();
        if ((status != null)) {
            TeamStatusEnum teamStatusEnum = TeamStatusEnum.getStatus(status);
            if (ObjectUtils.isEmpty(teamStatusEnum)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "修改状态不合法");
            }
            if (TeamStatusEnum.SECRET.equals(teamStatusEnum) && teamUpdateRequest.getPassword() == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "修改为加密状态必须要有密码");
            }
        }

        //6.更新成功
        //todo 按需修改 还是控制前端全部传入
        Team updateTeam = new Team();
        BeanUtils.copyProperties(teamUpdateRequest, updateTeam);
        updateTeam.setUpdateTime(LocalDateTime.now());

        boolean result = this.updateById(updateTeam);
        return result;
    }

    @Override
    public Boolean joinTeam(TeamJoinRequest teamJoinRequest) {

        /*
            1.队伍必须存在 && 未满 && 未过期
            2.用户最多加入5个队伍
            3.不能加入自己的队伍
            4.不能重复加入已加入的队伍
            5.禁止加入私有队伍
            6.如果队伍加密，必要密码匹配才可以
            7.新增队伍-用户关联信息
         */

        if (ObjectUtils.isEmpty(teamJoinRequest)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //1.队伍必须存在 && 未满 && 未过期
        Long teamId = teamJoinRequest.getTeamId();
        Team team = this.getById(teamId);
        if (ObjectUtils.isEmpty(team)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }
        Long teamNum = userTeamService
                .lambdaQuery()
                .eq(UserTeam::getTeamId, teamId)
                .count();
        if (teamNum >= team.getMaxNum()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人员已满");
        }
        LocalDateTime expireTime = team.getExpireTime();
        if (expireTime != null && LocalDateTime.now().isAfter(expireTime)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍已失效");
        }

        //2.用户最多加入5个队伍
        LoginUserVO loginUser = userService.getLoginUser();
        Long userId = loginUser.getId();
        Long maxJoinTeamNum = userTeamService
                .lambdaQuery()
                .eq(UserTeam::getUserId, userId)
                .count();
        if (maxJoinTeamNum >= 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多创建或加入5个队伍");
        }

        //3.不能加入自己的队伍
        Long createUserId = team.getUserId();
        if (userId.equals(createUserId)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "禁止加入自己的队伍");
        }

        //4.不能重复加入已加入的队伍
        Long joinCount = userTeamService.lambdaQuery()
                .eq(UserTeam::getUserId, userId)
                .eq(UserTeam::getTeamId, teamId)
                .count();
        if (joinCount > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能重复加入队伍");
        }

        //5.禁止加入私有队伍
        Integer status = team.getStatus();
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getStatus(status);
        if (TeamStatusEnum.PRIVATE.equals(teamStatusEnum)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "禁止加入私有队伍");
        }

        //6.如果队伍加密，必要密码匹配才可以
        if (TeamStatusEnum.SECRET.equals(teamStatusEnum)) {
            String password = teamJoinRequest.getPassword();
            if (StringUtils.isBlank(password) || !team.getPassword().equals(password)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
            }
        }

        //7.新增队伍-用户关联信息
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(LocalDateTime.now());

        boolean result = userTeamService.save(userTeam);

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean quitTeam(TeamQuitRequest teamQuitRequest) {
        /*
            1.校验请求参数
            2.校验队伍是否存在
            3.校验我是否加入队伍
            4.如果队伍只剩一人，解散队伍
            5.否则 分两种情况
                a.我是队长 顺位给下一个 (通过给id排序 只取前两个)
                b.队伍直接退出 无需对于操作
         */

        //1.校验请求参数
        if (ObjectUtils.isEmpty(teamQuitRequest)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //2.校验队伍是否存在
        long teamId = teamQuitRequest.getTeamId();
        Team team = this.getById(teamId);
        if (ObjectUtils.isEmpty(team)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求数据为空");
        }

        //3.校验我是否加入队伍
        LoginUserVO loginUser = userService.getLoginUser();
        Long userId = loginUser.getId();
        Long isJoinTeam = userTeamService.lambdaQuery()
                .eq(UserTeam::getTeamId, teamId)
                .eq(UserTeam::getUserId, userId)
                .count();
        if (isJoinTeam == 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "未加入该队伍");
        }

        //4.如果队伍只剩一人，解散队伍
        Long userTotalNum = userTeamService.lambdaQuery()
                .eq(UserTeam::getTeamId, teamId)
                .count();
        if (userTotalNum <= 1) {
            //删除队伍
            this.removeById(teamId);
            //删除用户队伍信息
            return userTeamService.removeById(teamId);
        } else {
            //5.否则 分两种情况
            //a.我是队长 顺位给下一个 (通过给id排序 只取前两个)
            if (Objects.equals(team.getUserId(), userId)) {
                List<UserTeam> userTeamList = userTeamService.lambdaQuery()
                        .eq(UserTeam::getTeamId, teamId)
                        .last("order by id asc limit 2")
                        .list();

                //将队长转移给第二位
                UserTeam userTeam = userTeamList.get(1);
                Long userLeaderId = userTeam.getUserId();
                LambdaUpdateWrapper<Team> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                lambdaUpdateWrapper.set(Team::getUserId, userLeaderId)
                        .eq(Team::getId, teamId);
                this.update(lambdaUpdateWrapper);


                //删除当前用户中队伍的相关信息
                LambdaQueryWrapper<UserTeam> queryWrapper = new LambdaQueryWrapper<UserTeam>()
                        .eq(UserTeam::getUserId, userId)
                        .eq(UserTeam::getTeamId, teamId);
                return userTeamService.remove(queryWrapper);
            } else {
                //b.队伍直接退出 无需对于操作
                //只需删除用户队伍表中的相关信息
                LambdaQueryWrapper<UserTeam> queryWrapper = new LambdaQueryWrapper<UserTeam>()
                        .eq(UserTeam::getUserId, userId);
                return userTeamService.remove(queryWrapper);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteTeam(long teamId) {
        /*
            1.检验请求参数
            2.检验队伍是否存在
            3.校验当前用户是否为队长
            4.移除所有加入队伍的关联信息
            5.移除队伍
         */

        //1.检验请求参数
        if (teamId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //2.检验队伍是否存在
        Team team = this.getById(teamId);
        if (ObjectUtils.isEmpty(team)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍不存在");
        }

        //3.校验当前用户是否为队长
        LoginUserVO loginUser = userService.getLoginUser();
        Long userId = loginUser.getId();
        if (Objects.equals(userId, team.getUserId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "没有权限");
        }

        //4.移除所有加入队伍的关联信息
        LambdaQueryWrapper<UserTeam>  queryWrapper = new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getId, teamId);
        userTeamService.remove(queryWrapper);

        //5.移除队伍
        return this.removeById(teamId);
    }

    @Override
    public List<UserTeamVO> listMyTeams() {
        //获得登录用户
        LoginUserVO loginUser = userService.getLoginUser();
        Long userId = loginUser.getId();

        //查询队伍
        List<Team> teamList = this.lambdaQuery()
                .eq(Team::getUserId, userId)
                .list();

        //遍历转换并存入登录用户信息
        return getUserTeamVOS(loginUser, teamList);
    }

    @Override
    public List<UserTeamVO> listMyJoinTeams() {
        /*
            1.查出当前用户加入all teamId
            2.通过teamId查出队伍，并查出该队伍的创建者
            3.转换成UserTeamVO返回
         */

        //1.查出当前用户加入all teamId
        LoginUserVO loginUser = userService.getLoginUser();
        Long userId = loginUser.getId();
        List<UserTeam> userTeamList = userTeamService.lambdaQuery()
                .eq(UserTeam::getUserId, userId)
                .list();
        Set<Long> teamIdSet = userTeamList.stream()
                .collect(Collectors.groupingBy(UserTeam::getTeamId))
                .keySet();

        //2.通过teamId查出队伍，并查出该队伍的创建者
        //3.转换成UserTeamVO返回

        List<UserTeamVO> userTeamVOList = new ArrayList<>();
        for (Long teamId : teamIdSet) {
            Team team = this.getById(teamId);
            Long createUserId = team.getUserId();
            User user = userService.getById(createUserId);

            UserTeamVO userTeamVO = new UserTeamVO();
            BeanUtils.copyProperties(team, userTeamVO);
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            userTeamVO.setCreateUserVO(userVO);

            userTeamVOList.add(userTeamVO);
        }

        return userTeamVOList;
    }

    @NotNull
    private List<UserTeamVO> getUserTeamVOS(LoginUserVO loginUser, List<Team> teamList) {
        List<UserTeamVO> userTeamVOList = new ArrayList<>();
        for (Team team : teamList) {
            UserTeamVO userTeamVO = new UserTeamVO();
            BeanUtils.copyProperties(team, userTeamVO);
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(loginUser, userVO);
            userTeamVO.setCreateUserVO(userVO);
            userTeamVOList.add(userTeamVO);
        }

        return userTeamVOList;
    }
}




